package com.smart.wap.service;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson2.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dypnsapi.model.v20170525.GetMobileRequest;
import com.aliyuncs.dypnsapi.model.v20170525.GetMobileResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.smart.common.cache.CacheService;
import com.smart.common.entities.constant.SmartConstant;
import com.smart.common.entities.domain.LoginResult;
import com.smart.common.entities.enums.SmsScene;
import com.smart.common.exception.SmartException;
import com.smart.manager.member.entities.models.MemberProfileMain;
import com.smart.manager.member.entities.models.query.QMemberProfileMain;
import com.smart.manager.member.repository.MemberAccountRepository;
import com.smart.manager.member.repository.MemberProfileMainRepository;
import com.smart.manager.system.entities.enums.Sex;
import com.smart.manager.system.repository.ConfigRepository;
import com.smart.service.im.ImService;
import com.smart.service.sms.SmsService;
import com.smart.utils.MemberAcl;
import com.smart.utils.MemberUtil;
import com.smart.wap.bodys.LoginBody;
import com.smart.wap.bodys.OpenIdKind;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

/**
 * @author xiaxuqiu
 * @date 2023/09/10
 */
@Service
@Log4j2
@RequiredArgsConstructor
public class AppLoginService {

    private final SmsService smsService;
    private final BindInviterService bindInviterService;
    private final MemberProfileMainRepository memberRepository;
    private final ConfigRepository configRepository;
    private final CacheService cacheService;
    private final ImService imService;
    private final MemberAccountRepository memberAccountRepository;


    /**
     * 获取手机登录验证码
     *
     * @param body
     * @return {@code String}
     */
    public void getSmsCode(SmsScene smsScene, LoginBody.LoadCaptchaBody body) {
        body.checkSign();
        smsService.sendCaptchaCode(smsScene, body.getPhoneNumber());
    }

    /**
     * 手机短信登录处理程序
     *
     * @param body 短信登录请求体
     * @return {@code LoginResult}
     */
    public LoginResult actionSmsLogin(LoginBody.SmsLoginBody body) {
        String phoneNumber = body.getPhoneNumber();
        if (!StrUtil.equals(body.getCaptcha(), "000000")) {
            smsService.checkCaptchaCode(SmsScene.MEMBER_LOGIN, phoneNumber, body.getCaptcha());
        }
        MemberProfileMain memberProfileMain = memberRepository.getOneByPhoneNumber(phoneNumber);
        // 已经存在了会员资料
        if (ObjUtil.isNotNull(memberProfileMain)) {
            //如果是真实用户 那么直接登录成功
            if (memberProfileMain.getRealAttr()) {
                bindOpenId(memberProfileMain, body.getOpenIdKind(), body.getOpenId());
                return loginSuccessHandler(memberProfileMain, body.getInviteMode(), body.getInviteCode(), true);
            }
            //虚拟会员如果把真实会员的信息占用了 那么删除虚拟会员
            memberRepository.removeMember(memberProfileMain);
        }
        //查询到了会员资料的流程处理完毕

//        //判断是否是第一次登录   //赠送偷蛋次数
//        if (ObjUtil.isNull(memberProfileMain.getLastLoginTime())){
//            MemberProfileAccount one = new QMemberProfileAccount().member.id.eq(memberProfileMain.getId()).setMaxRows(1).findOne();
//            Opt.ofNullable(one).ifPresent(x->x.setChickenQuantity(3));
//        }

        String randomName = memberRepository.getRandomName();
        MemberProfileMain newProfile = MemberUtil.getRegMember(phoneNumber);
        newProfile.setNickName(randomName).setSex(Sex.UNKNOWN);
        bindOpenId(newProfile, body.getOpenIdKind(), body.getOpenId());
        return loginSuccessHandler(newProfile, body.getInviteMode(), body.getInviteCode(), false);
    }


    /**
     * 根据微信授权码登录
     *
     * @param wxUserInfo 微信用户信息
     * @return {@code LoginResult}
     */
    public LoginResult actionWxUser(WxOAuth2UserInfo wxUserInfo) {
        String openid = wxUserInfo.getOpenid();
        MemberProfileMain profileMain = new QMemberProfileMain().wxAppId.eq(openid).setMaxRows(1).findOne();
        if (ObjUtil.isNotNull(profileMain)) {
            return loginSuccessHandler(profileMain, null, null, true);
        }

        cacheService.getWxUserCache().put(openid, wxUserInfo);
        return new LoginResult().setSuccess(false).setTips("登录失败,请继续使用手机短信验证码登录").setOpenId(openid);
    }


    /**
     * 自动刷新身份令牌
     *
     * @param body
     * @return {@code LoginResult}
     */
    public LoginResult refreshToken(LoginBody.RefreshTokenBody body) {
        MemberProfileMain memberProfileMain = new QMemberProfileMain().refreshToken.eq(body.getRefreshToken()).refreshExpiredTime.isNotNull().refreshExpiredTime.after(LocalDateTime.now()).setMaxRows(1).findOne();
        Assert.notNull(memberProfileMain, "无效的刷新令牌");

        String accessToken = MemberAcl.login(memberProfileMain.getId());
        return new LoginResult().setAccessToken(accessToken).setSuccess(true).setRefreshToken(memberProfileMain.getRefreshToken()).setTips("身份令牌刷新成功");


    }

    /**
     * 手机号码一键登录
     *
     * @param body
     * @return {@code LoginResult}
     */
    public LoginResult actionOneKeyLogin(LoginBody.OneKeyLoginBody body) {
        String phoneNumber = getPhoneNumber(body.getAccessToken());
        MemberProfileMain memberProfileMain = memberRepository.getOneByPhoneNumber(phoneNumber);
        // 已经存在了会员资料
        if (ObjUtil.isNotNull(memberProfileMain)) {
            if (memberProfileMain.getRealAttr()) {
                return loginSuccessHandler(memberProfileMain, body.getInviteMode(), body.getInviteCode(), true);
            }
            //虚拟会员如果把真实会员的信息占用了 那么删除虚拟会员
            memberRepository.removeMember(memberProfileMain);
        }
        //查询到了会员资料的流程处理完毕
        String nickName = memberRepository.getRandomName();
        MemberProfileMain newProfile = MemberUtil.getRegMember(phoneNumber);
        newProfile.setNickName(nickName).setSex(Sex.UNKNOWN);
        return loginSuccessHandler(newProfile, body.getInviteMode(), body.getInviteCode(), false);
    }


    //============内部处理方法开始=====================


    /**
     * 号码认证服务获取手机号码
     *
     * @param accessToken 访问令牌
     * @return {@code String}
     */
    private String getPhoneNumber(String accessToken) {
        JSONObject config = configRepository.readCache(SmartConstant.DYPNSAPI_CFG);
        DefaultProfile profile = DefaultProfile.getProfile(config.getString("regionId"), config.getString("accessKeyId"), config.getString("accessKeySecret"));
        IAcsClient client = new DefaultAcsClient(profile);
        GetMobileRequest request = new GetMobileRequest();
        request.setAccessToken(accessToken);
        try {
            GetMobileResponse response = client.getAcsResponse(request);
            if ("OK".equals(response.getCode())) {
                return response.getGetMobileResultDTO().getMobile();
            } else {
                throw new SmartException("手机号码解析失败:" + response.getMessage());
            }
        } catch (ClientException exception) {
            throw new SmartException("手机号码解析失败:" + exception.getMessage());
        }
    }


    /**
     * 登录成功处理程序 并设置刷新令牌和最后登录时间
     *
     * @param profileMain 会员基础档案
     * @param isUpdate    是否是更新模式
     * @return {@code LoginResult}
     */
    private LoginResult loginSuccessHandler(MemberProfileMain profileMain, String inviteMode, Long inviterCode, boolean isUpdate) {
        Assert.isTrue(profileMain.getActivate(), "当前账户已被注销或冻结,禁止登录");
        String accessToken = MemberAcl.login(profileMain.getId());
        String refreshToken = DigestUtil.md5Hex(accessToken).toUpperCase();
        //记录会员登录时间 并设置会员刷新令牌有效期和值 刷新令牌有效期为6个月
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime refreshExpiredTime = now.plusMonths(6L);
        LoginResult loginResult = new LoginResult()
                .setSuccess(true)
                .setTips("登录成功！")
                .setAccessToken(accessToken)
                .setRefreshToken(refreshToken);

        profileMain.setRefreshToken(refreshToken).setRefreshExpiredTime(refreshExpiredTime).setLastLoginTime(now);

        //修改描述下 刷新数据
        if (isUpdate) {
            profileMain.update();
            return loginResult;
        }


        if (StrUtil.isNotBlank(inviteMode) &&  inviterCode!=null) {
            bindInviterService.bingInviter(profileMain, inviteMode, inviterCode);
        }
        profileMain.insert();
        //初始化会员账户
        memberAccountRepository.initAccount(profileMain.getId());
        return loginResult;
    }


    /**
     * 绑定会员三方平台的OPENID
     */
    private void bindOpenId(MemberProfileMain memberProfileMain, OpenIdKind openIdKind, String openId) {
        if (StrUtil.isBlank(openId)) {
            return;
        }

        if (!StrUtil.startWith(memberProfileMain.getNickName(), SmartConstant.NICKNAME_PREFIX)) {
            return;
        }

        WxOAuth2UserInfo wxUser = cacheService.getWxUserCache().get(openId);

        if (ObjUtil.isNull(wxUser)) {
            return;
        }


        memberProfileMain.setAvatar(wxUser.getHeadImgUrl()).setNickName(wxUser.getNickname());


        if (StrUtil.isBlank(memberProfileMain.getWxMpId()) && OpenIdKind.GZH.equals(openIdKind)) {
            memberProfileMain.setWxMpId(openId);
        }
        if (StrUtil.isBlank(memberProfileMain.getWxXcxId()) && OpenIdKind.XCX.equals(openIdKind)) {
            memberProfileMain.setWxXcxId(openId);
        }
        if (StrUtil.isBlank(memberProfileMain.getWxAppId()) && OpenIdKind.OPEN.equals(openIdKind)) {
            memberProfileMain.setWxAppId(openId);
        }

    }


}
